home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Environments / Clean 1.2.4 / IO Examples / Worm / worm.icl next >
Encoding:
Text File  |  1997-05-01  |  11.7 KB  |  338 lines  |  [TEXT/3PRM]

  1. module worm
  2.  
  3. /*    The famous Unix game 'worm' (or 'snake') in Concurrent Clean.
  4.     This program requires the 0.8 I/O library.
  5.     Run the program using the "No Console" option (Application options).
  6. */
  7.  
  8. import StdBool, StdChar, StdString, StdFile, StdArray, StdList, StdTuple, StdEnum
  9. import deltaDialog, deltaEventIO, deltaWindow, deltaMenu, deltaTimer, deltaSystem
  10. import wormshow, wormstate, Help
  11.  
  12. //    GUI constants.
  13. FileID            :== 1
  14. PlayID                :== 11
  15. InterruptID            :== 12
  16. HaltID                    :== 121
  17. ContID                    :== 122
  18. QuitID                :== 13
  19. LevelID            :== 2
  20. EasyID                :== 21
  21. MediumID            :== 22
  22. HardID                :== 23
  23. HiScoreID            :== 24
  24.  
  25. HighDlogID        :== 1000
  26. OverDlogID        :== 2000
  27.  
  28. WindowID        :== 1
  29. WdPicSize        :== ((0,0),(488,303))
  30.  
  31. TimerID            :== 1
  32.  
  33. HelpFile        :== "WormHelp"
  34. HiScoresFile    :== "wormhi"
  35. NrOfHiScores    :== 8
  36.  
  37. //    Start of the program.
  38. Start :: *World -> *World
  39. Start world
  40. #    (events,world)    = OpenEvents world
  41.     (files, world)    = openfiles  world
  42.     (about,files)    = MakeAboutDialog "Worm" HelpFile files Help
  43.     (hifile,best)    = ReadHiScores HiScoresFile files
  44.     (state,events)    = StartIO [DialogSystem [about], menu, window, timer] (InitState best) init_io events
  45.     files            = WriteHiScores hifile state.best
  46.     world            = closefiles  files  world
  47.     world            = CloseEvents events world
  48. =    world
  49. where
  50.     init_io            = [    initFoodSupply
  51.                       ,    initWindowPicture
  52.                       ]
  53.     initFoodSupply state=:{worm,level} io
  54.     #    (seed,io)        = GetNewRandomSeed io
  55.         foods            = FoodSupply seed
  56.         (food,foods)    = NewFood worm level foods
  57.     =    ({state & food=food,foodsupply=foods}, io)
  58.     initWindowPicture state io
  59.     =    (state, DrawInWindow WindowID [SetBackColour WormBackGroundColour,SetFontSize WormFontSize] io)
  60.     
  61.     menu            = MenuSystem 
  62.                         [    PullDownMenu FileID "File" Able
  63.                             [    MenuItem PlayID "Play"     (Key 'R') Able Play
  64.                             ,    MenuItemGroup InterruptID [MenuItem HaltID "Halt" (Key '.') Unable Halt]
  65.                             ,    MenuSeparator
  66.                             ,    MenuItem QuitID "Quit"     (Key 'Q') Able Quit
  67.                             ]
  68.                         ,    PullDownMenu LevelID "Options" Able
  69.                             [    MenuRadioItems EasyID 
  70.                                 [    MenuRadioItem EasyID   "Slow"   (Key '1') Able (SetSpeed EasySpeed)
  71.                                 ,    MenuRadioItem MediumID "Medium" (Key '2') Able (SetSpeed MediumSpeed)
  72.                                 ,    MenuRadioItem HardID   "Fast"   (Key '3') Able (SetSpeed HardSpeed)
  73.                                 ]
  74.                             ,    MenuSeparator
  75.                             ,    MenuItem HiScoreID "High Scores" (Key 'H') Able ShowBest
  76.                             ]
  77.                         ]
  78.     window            = WindowSystem 
  79.                         [    FixedWindow WindowID (0,0) "Worm" WdPicSize UpdateWindow
  80.                             [    GoAway        Quit
  81.                             ,    Keyboard    Unable MakeTurn
  82.                             ]
  83.                         ]
  84.     timer            = TimerSystem 
  85.                         [    Timer TimerID Unable EasySpeed OneStep
  86.                         ]
  87.  
  88.  
  89. //    The update function for the playfield window.
  90. UpdateWindow :: UpdateArea State -> (State, [DrawFunction])
  91. UpdateWindow _ state=:{level,food,points,worm,lives}
  92. =    (state, DrawGame level food points worm lives)
  93.  
  94.  
  95. //    The function for the Help button of the about dialog
  96. Help :: State (IOState State) -> (State, IOState State)
  97. Help state=:{best=(files,hs)} io
  98. #    (files,io)    = ShowHelp HelpFile files io
  99. =    ({state & best=(files,hs)}, io)
  100.  
  101.  
  102. //    The function for the Play command.
  103. Play :: State (IOState State) -> (State, IOState State)
  104. Play state=:{level={fix,speed},foodsupply} io
  105. #    io    = ActivateWindow    WindowID            io
  106.     io    = DisableMenus        [LevelID]            io
  107.     io    = DisableMenuItems    [PlayID,QuitID]        io
  108.     io    = EnableMenuItems    [HaltID]            io
  109.     io    = SetTimerInterval    TimerID  speed        io
  110.     io    = EnableKeyboard    WindowID            io
  111.     io    = EnableTimer        TimerID                io
  112.     io    = DrawInWindow        WindowID (DrawGame initlevel newfood initpoints initworm initlives)
  113.                                                     io
  114.     io    = ChangeWindowCursor WindowID HiddenCursor    io
  115. =    (initstate, io)
  116. where
  117.     initlevel        = InitLevel fix
  118.     initworm        = NewWorm initlevel
  119.     (newfood,foods1)= NewFood initworm initlevel foodsupply
  120.     initpoints        = 0
  121.     initlives        = NrOfWorms
  122.     initstate        = {state & level        = initlevel
  123.                              , food            = newfood
  124.                              , foodsupply    = foods1
  125.                              , grow            = 0
  126.                              , points        = initpoints
  127.                              , dir            = RightKey
  128.                              , worm            = initworm
  129.                              , lives        = initlives
  130.                       }
  131.  
  132.  
  133. //    The functions for the Halt/Continue command(s).
  134. Halt :: State (IOState State) -> (State, IOState State)
  135. Halt state io
  136. #    io            = DisableKeyboard     WindowID                    io
  137.     io            = DisableTimer         TimerID                    io
  138.     io            = EnableMenuItems     [QuitID]                    io
  139.     io            = RemoveMenuItems     [HaltID]                    io
  140.     io            = InsertMenuItems     InterruptID 1 [continue]    io
  141.     io            = ChangeWindowCursor WindowID StandardCursor    io
  142. =    (state, io)
  143. where
  144.     continue    = MenuItem ContID "Continue" (Key '.') Able Continue
  145.     
  146.     Continue :: State (IOState State) -> (State, IOState State)
  147.     Continue state io
  148.     #    io        = ActivateWindow     WindowID                io
  149.         io        = DisableMenuItems     [QuitID]                io
  150.         io        = RemoveMenuItems     [ContID]                io
  151.         io        = InsertMenuItems     InterruptID 1 [halt]    io
  152.         io        = EnableKeyboard     WindowID                io
  153.         io        = EnableTimer         TimerID                io
  154.         io        = ChangeWindowCursor WindowID HiddenCursor    io
  155.     =    (state, io)
  156.     where
  157.         halt    = MenuItem HaltID "Halt" (Key '.') Able Halt
  158.  
  159.  
  160. //    The function for the Quit command: stop the program.
  161. Quit :: State (IOState State) -> (State, IOState State)
  162. Quit state io = (state, QuitIO io)
  163.  
  164.  
  165. //    Set a new speed (called when one of the Options commands is chosen).
  166. SetSpeed :: Int State (IOState State) -> (State, IOState State)
  167. SetSpeed fix state=:{State | level} io
  168. =    ({State | state & level={level & fix=fix,speed=fix}}, io)
  169.  
  170.  
  171. //    Show the high scores.
  172. ShowBest :: State (IOState State) -> (State, IOState State)
  173. ShowBest state=:{best=(_,highs)} io
  174. =    ShowHiScores HighDlogID "Worm High Scores:" highs state io
  175.  
  176.  
  177. //    The MakeTurn function is called when a key is pressed.
  178. MakeTurn :: KeyboardState State (IOState State) -> (State, IOState State)
  179. MakeTurn (key,KeyDown,_) state=:{dir} io
  180. |    (dir==UpKey   || dir==DownKey)  && (key==LeftKey || key==RightKey)    = OneStep 1 {state & dir=key} io
  181. |    (dir==LeftKey || dir==RightKey) && (key==UpKey   || key==DownKey )    = OneStep 1 {state & dir=key} io
  182. |    otherwise                                                            = (state,io)
  183. MakeTurn _ state io
  184. =    (state,io)
  185.  
  186.  
  187. //    The function for the Timer device: do one step of the worm game.
  188. OneStep :: TimerState State (IOState State) -> (State, IOState State)
  189. OneStep _ state=:{level,food,foodsupply,grow,points,dir,worm,best,lives} io
  190. |    newlevel<>curlevel    = SwitchLevel level foodsupply points2 points best lives io
  191. #    state                = {state & food=food1,foodsupply=foods1,grow=grow1,points=points2,worm=worm1}
  192. |    collide                = NextLife state io
  193. #    io                    = DrawInWindow WindowID [DrawStep scored food food1 points2 (hd worm) head tail] io
  194. |    scored                = (state,Beep io)
  195. |    otherwise            = (state,io)
  196. where
  197.     (head,tail,worm1)    = StepWorm dir grow worm
  198.     scored                = head==food.pos
  199.     collide                = Collision level worm head
  200.     value                = food.value
  201.     (food1,foods1)        = if scored (NewFood worm1 level foodsupply) (food,foodsupply)
  202.     grow1                = if scored (grow+value*3/2) (max 0 (grow-1))
  203.     points1                = if scored (points+value*(length worm1)/2) points
  204.     points2                = if collide (max 0 (points1-100)) points1
  205.     curlevel            = points /PointsPerLevel
  206.     newlevel            = points2/PointsPerLevel
  207.     
  208.     Collision :: Level Worm Segment -> Bool
  209.     Collision level worm head
  210.     |    not (InRectangle head ((1,1),(SizeX,SizeY)))    = True
  211.     |    any (InRectangle head) level.obstacles            = True
  212.     |    otherwise                                        = isMember head worm
  213.     where
  214.         InRectangle :: Point Obstacle -> Bool
  215.         InRectangle (x,y) ((lx,ty),(rx,by))    = x>=lx && x<=rx && y>=ty && y<=by
  216.     
  217.     StepWorm :: Direction Grow Worm -> (Segment,Segment,Worm)
  218.     StepWorm dir 0 worm
  219.     =    (head,tail,[head:worm1])
  220.     where
  221.         (tail,worm1)= GetAndRemoveLast worm
  222.         head        = NewHead dir (hd worm)
  223.         
  224.         GetAndRemoveLast :: ![.x] -> (.x,![.x])
  225.         GetAndRemoveLast [x]
  226.         =    (x,[])
  227.         GetAndRemoveLast [x:xs]
  228.         =    (x1,[x:xs1])
  229.         where
  230.             (x1,xs1)    = GetAndRemoveLast xs
  231.     StepWorm dir _ worm
  232.     =    (head,(0,0),[head:worm])
  233.     where
  234.         head    = NewHead dir (hd worm)
  235.     
  236.     NewHead :: Direction Segment -> Segment
  237.     NewHead UpKey    (x,y) = (x,  y-1)
  238.     NewHead DownKey  (x,y) = (x,  y+1)
  239.     NewHead LeftKey  (x,y) = (x-1,y)
  240.     NewHead RightKey (x,y) = (x+1,y)
  241.     
  242.     SwitchLevel :: Level [Food] Points Points HiScores Lives (IOState State) -> (State,IOState State)
  243.     SwitchLevel curlevel foods newPoints oldPoints high lives io
  244.     =    (newstate,NextLevelAnimation io)
  245.     where    
  246.         newlevel        = if (newPoints>oldPoints) (IncreaseLevel curlevel) (DecreaseLevel curlevel)
  247.         initworm        = NewWorm newlevel
  248.         (newfood,foods1)= NewFood initworm newlevel foods
  249.         newstate        = {    level        = newlevel
  250.                           ,    food        = newfood
  251.                           ,    foodsupply    = foods1
  252.                           ,    grow        = 0
  253.                           ,    points        = newPoints
  254.                           ,    dir            = RightKey
  255.                           ,    worm        = initworm
  256.                           ,    best        = high
  257.                           ,    lives        = if (newPoints>oldPoints) (lives+1) (lives-1)
  258.                           }
  259.         
  260.         NextLevelAnimation :: (IOState State) -> IOState State
  261.         NextLevelAnimation io
  262.         #    io    = ChangeTimerFunction    TimerID (BetweenLevels nrAnimationSteps (-1))    io
  263.             io    = SetTimerInterval        TimerID (TicksPerSecond/30)        io
  264.             io    = DisableActiveKeyboard                                    io
  265.         =    io
  266.         where
  267.             nrAnimationSteps= 40
  268.             
  269.             BetweenLevels :: Int Int TimerState State (IOState State) -> (State, IOState State)
  270.             BetweenLevels animationStep step _ state=:{level,food,points,worm,lives} io
  271.             |    animationStep<=1
  272.             =    (state, ChangeTimerFunction TimerID (BetweenLevels 2 1) io)
  273.             |    animationStep<=nrAnimationSteps
  274.             =    (state, io2)
  275.                 with
  276.                     io1        = DrawInActiveWindow [DrawAnimation animationStep step] io
  277.                     io2        = ChangeTimerFunction TimerID (BetweenLevels (animationStep+step) step) io1
  278.             #    io            = DrawInWindow            WindowID (DrawGame level food points worm lives) io
  279.                 io            = SetTimerInterval        TimerID level.speed    io
  280.                 io            = ChangeTimerFunction    TimerID OneStep        io
  281.                 io            = EnableActiveKeyboard                        io
  282.             =    (state,io)
  283.     
  284.     NextLife :: State (IOState State) -> (State, IOState State)
  285.     NextLife state=:{level,foodsupply,points,best=(_,highs),worm,lives} io
  286.     |    lives>0
  287.     =    ({state & food=newfood,foodsupply=foods1,grow=0,dir=RightKey,worm=newworm,lives=lives-1},DeadWormAlert worm io)
  288.         with
  289.             (newfood,foods1)= NewFood newworm level foodsupply
  290.             newworm            = NewWorm level
  291.             
  292.             DeadWormAlert :: Worm (IOState State) -> IOState State
  293.             DeadWormAlert worm io
  294.             #    io            = ChangeTimerFunction    TimerID (DeadWorm worm)        io
  295.                 io            = SetTimerInterval        TimerID (TicksPerSecond/30)    io
  296.                 io            = DisableActiveKeyboard                                io
  297.             =    io
  298.             where
  299.                 DeadWorm :: Worm TimerState State (IOState State) -> (State, IOState State)
  300.                 DeadWorm [segment:rest] _ state io
  301.                 #    io        = DrawInWindow WindowID [EraseSegment segment] io
  302.                 =    (state, ChangeTimerFunction TimerID (DeadWorm rest) io)
  303.                 DeadWorm _ _ state=:{level,food,points,worm,lives} io
  304.                 #    io        = DrawInWindow WindowID (DrawGame level food points worm lives)    io
  305.                     io        = ChangeTimerFunction    TimerID OneStep                            io
  306.                     io        = SetTimerInterval        TimerID level.speed                        io
  307.                     io        = EnableActiveKeyboard                                            io
  308.                 =    (state, io)
  309.     #    io        = EnableMenus         [LevelID]            io
  310.         io        = EnableMenuItems     [PlayID,QuitID]    io
  311.         io        = DisableMenuItems     [HaltID]            io
  312.         io        = DisableTimer         TimerID            io
  313.         io        = DisableKeyboard     WindowID            io
  314.         io        = ChangeWindowCursor WindowID StandardCursor io
  315.     |    ItsAHighScore NrOfHiScores points highs
  316.     =    OpenModalDialog dialog state io
  317.         with
  318.             dialog    = CommandDialog OverDlogID "Game Over"
  319.                         [    ItemSpace    (MM 6.0) (MM 6.0)
  320.                         ]    4
  321.                         [    StaticText        1 Left        "Game Over with a new high score!"
  322.                         ,    StaticText        2 Left        "Your name:"
  323.                         ,    EditText        3 (RightTo 2) (MM 45.0) 1 ""
  324.                         ,    DialogButton    4 Center    "OK" Able OverOK
  325.                         ]
  326.             OverOK :: DialogInfo State (IOState State) -> (State, IOState State)
  327.             OverOK dialog state=:{points,best=(files,highs)} io
  328.             #    io            = CloseActiveDialog io
  329.             |    name==""    = (state, io)
  330.             #    highs        = AddScore NrOfHiScores {name=name,score=points} highs
  331.                 state        = {state & best=(files,highs)}
  332.             |    otherwise    = (state, io)
  333.             where
  334.                 name        = GetEditText 3 dialog
  335.     #    (_,state,io)    = OpenNotice (Notice ["Game Over, no high score."] (NoticeButton 1 "OK") []) state io
  336.     |    otherwise
  337.     =    (state,io)
  338.